package com.hk.web.controller.api;

import com.hk.commons.JsonResult;
import com.hk.commons.ProcessAPI;
import com.hk.commons.domain.service.ValidateService;
import com.hk.commons.exceptions.SystemException;
import com.hk.commons.exceptions.UserNotExistException;
import com.hk.commons.exceptions.ValidateException;
import com.hk.commons.service.ImageCaptchaService;
import com.hk.commons.service.RedisService;
import com.hk.commons.utils.CglibBeanUtils;
import com.hk.web.context.UserContext;
import com.hk.web.controller.Routes;
import com.hk.web.domain.entity.User;
import com.hk.web.dto.*;
import com.hk.web.domain.lifeCycle.constants.CacheConstants;
import com.octo.captcha.service.CaptchaServiceException;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.client.RestTemplate;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.InvocationTargetException;
import java.util.HashMap;

/**
 * Created by Antinomy on 16/10/13.
 */

@RestController
@Api(value = "权限验证模块", description = "权限验证模块")
@RequestMapping(Routes.AUTH)
public class AuthController {

    @Value("${producer.host}")
    private String host;

    private RestTemplate template = new RestTemplate();

    public static final String PASSWORD_LOGIN_TYPE = "2";
    private Logger logger = LoggerFactory.getLogger(AuthController.class);

    @Autowired
    private UserContext userContext;

    @ApiOperation(value = "登录验证", notes = "登录验证", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @RequestMapping(value = Routes.AUTH_USER, method = RequestMethod.POST)
    @ResponseBody
    public JsonResult login(HttpServletRequest request, @RequestBody LoginDTO loginDTO,@PathVariable String mobile) {

        ProcessAPI api = (jsonResult, validate) -> {

            String name = validate.checkAndPrepare("mobile", mobile);
            String loginType = validate.checkAndPrepare("loginType", loginDTO.getLoginType());
            String captchaId = validate.checkAndPrepare("verifySource", loginDTO.getVerifySource());
            String response = validate.checkAndPrepare("verifyCode", loginDTO.getVerifyCode());

            User user = userContext.findUserByName(name);
            boolean isExist = (user == null || (user.getIsInside() !=null && user.getIsInside() ==0));
            if(isExist){
                throw new UserNotExistException("此用户不存在");
            }
            if(user.getOnType() != null && user.getOnType() ==1){
                throw new ValidateException("用户离职，不能登录");
            }

            validateCaptcha(captchaId, response);

            // 密码登陆
            if (loginType.equals(PASSWORD_LOGIN_TYPE)) {
                String pwd = validate.checkAndPrepare("pwd", loginDTO.getPwd());

                validateOldPassword(user, pwd);

            } else {
                throw new ValidateException("只支持密码验证");
            }

            UserDTO userDTO = new UserDTO();
            CglibBeanUtils.copy(userDTO,user);

            String token = RandomStringUtils.randomAlphanumeric(64);
            userDTO.setToken(token);

            String key = CacheConstants.UserLog_Token + user.getId();
            RedisService.setString(key, token, CacheConstants.LOGIN_TOKEN_EXPIRE);

            HashMap result = renderResult(userDTO);
            jsonResult.result = result;
        };

        return api.process(request);
    }




    @ApiOperation(value = "修改密码", notes = "修改密码", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @RequestMapping(value = Routes.AUTH_CHANGE_PWD, method = RequestMethod.PUT)
    @ResponseBody
    public JsonResult changePassword(HttpServletRequest request, @RequestBody ChangePwdDTO dto, @PathVariable String mobile) {

        ProcessAPI api = (jsonResult, validate) -> {

            changePassword(dto, mobile, validate);

            jsonResult.result = "修改密码成功";
        };

        return api.process(request);
    }

    @ApiOperation(value = "修改密码", notes = "修改密码", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @RequestMapping(value = Routes.AUTH_CHANGE_PWD, method = RequestMethod.POST)
    @ResponseBody
    public JsonResult changePasswordForPost(HttpServletRequest request, @RequestBody ChangePwdDTO dto, @PathVariable String mobile) {

        ProcessAPI api = (jsonResult, validate) -> {

            changePassword(dto, mobile, validate);

            jsonResult.result = "修改密码成功";
        };

        return api.process(request);
    }

    @ApiOperation(value = "忘记密码", notes = "忘记密码", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)
    @RequestMapping(value = Routes.AUTH_FORGET_PWD, method = RequestMethod.POST)
    @ResponseBody
    public JsonResult forgetPasswordForPost(HttpServletRequest request, @RequestBody ForgetPwdDTO dto, @PathVariable String mobile) {

        ProcessAPI api = (jsonResult, validate) -> {

            forgetPassword(dto, mobile, validate);

            jsonResult.result = "修改密码成功";
        };

        return api.process(request);
    }

    private void changePassword(@RequestBody ChangePwdDTO dto, @PathVariable String mobile, ValidateService validate) {
        String name = validate.checkAndPrepare("mobile", mobile);
        String captchaId = validate.checkAndPrepare("verifySource", dto.getVerifySource());
        String response = validate.checkAndPrepare("verifyCode", dto.getVerifyCode());

        User user = userContext.findUserByName(name);

        //验证图形验证码
        validateCaptcha(captchaId, response);

        String oldPwd = validate.checkAndPrepare("oldPwd", dto.getOldPwd());
        String newPwd = validate.checkAndPrepare("pwd", dto.getPwd());

        validateOldPassword(user,oldPwd);

        Integer changeCount = userContext.updatePassword(name, newPwd);

        if (changeCount != 1) {
            throw new SystemException("修改密码失败,请稍后再试!"); }
    }


    private void forgetPassword( ForgetPwdDTO dto, String mobile, ValidateService validate  ) {
        String name = validate.checkAndPrepare("mobile", mobile);
        String phoneCode = validate.checkAndPrepare("verifyCode", dto.getVerifyCode());

        String pwd = validate.checkAndPrepare("pwd", dto.getPwd());

        //检查用户是否存在
        userContext.findUserByName(name);

        //短信验证码
        validatePhoneCode(mobile, phoneCode);


        Integer changeCount = userContext.updatePassword(name, pwd);

        if (changeCount != 1) {
            throw new SystemException("修改密码失败,请稍后再试!");
        }
    }


    private void validateCaptcha(String captchaId, String response) {
        //验证图形验证码
        try {
            Boolean isResponseCorrect = Boolean.FALSE;
            isResponseCorrect = ImageCaptchaService.getInstance().validateResponseForID(captchaId, response);
            if (isResponseCorrect.equals(Boolean.FALSE))
                throw new ValidateException("图形验证码输入错误");
        } catch (CaptchaServiceException e) {
            //should not happen, may be thrown if the id is not valid
            logger.error(e.getMessage());
            throw new SystemException("图形验证码已经失效");
        }
    }

    private boolean validatePhoneCode(String mobile, String response) {
        Boolean returnVal = false;


        CheckMsgCodeDTO checkMsgCodeDTO = new CheckMsgCodeDTO();

        checkMsgCodeDTO.setName(mobile);
        checkMsgCodeDTO.setMsgCode(response);
        String url = "http://" + host + "/userInfo/checkMsgCode";
        try {
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.APPLICATION_JSON);
            HttpEntity<Object> requestEntity = new HttpEntity<>(checkMsgCodeDTO,
                    headers);
            HashMap postResult = template.postForObject(url, requestEntity, HashMap.class);

            Boolean checkResult = (Boolean) postResult.get("result");
            logger.info("checkResult = {}", checkResult);

            if (!checkResult) {
                logger.info("验证码不正确或已超时！");
                throw new ValidateException("验证码不正确或已超时");
            } else {
                returnVal = true;
            }
        } catch (Exception e) {

            logger.error("验证码检测异常！", e);
            throw new ValidateException("验证码不正确或已超时");

        }
        return returnVal;
    }

    private void validateOldPassword(User user, String pwd) {
        if (!user.getPwd().equalsIgnoreCase(pwd)) {
            logger.error("{} diff {}", user.getPwd(), pwd);

            throw new ValidateException("密码错误，请重新输入");
        }
    }

    private HashMap renderResult(UserDTO user) {
        HashMap result = new HashMap();
        result.put("id", user.getId());
        result.put("realName", user.getRealName());
        result.put("name", user.getName());
        return result;
    }



}
